package com.gkzf.ai.module.crm.service.creditReport;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gkzf.ai.framework.common.enums.UserTypeEnum;
import com.gkzf.ai.framework.common.util.object.BeanUtils;
import com.gkzf.ai.framework.tenant.core.context.TenantContextHolder;
import com.gkzf.ai.framework.websocket.core.sender.local.LocalWebSocketMessageSender;
import com.gkzf.ai.module.crm.config.BaseService;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.*;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.creditreportbasic.CreditReportBasicSaveReqVO;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.creditreportdetails.CreditReportDetailsRespVO;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.creditreportdetails.CreditReportDetailsSaveReqVO;
import com.gkzf.ai.module.crm.dal.dataobject.creditReport.CreditReportBasicDO;
import com.gkzf.ai.module.crm.dal.dataobject.creditReport.CreditReportDetailsDO;
import com.gkzf.ai.module.crm.dal.dataobject.creditReport.UserCreditReportAdmittanceConditionDO;
import com.gkzf.ai.module.crm.dal.dataobject.product.CrmProductDO;
import com.gkzf.ai.module.crm.dal.dataobject.product.ProductAdmittanceConditionDO;
import com.gkzf.ai.module.crm.dal.mysql.creditReport.CreditReportAdmittanceConditionMapper;
import com.gkzf.ai.module.crm.dal.mysql.creditReport.CreditReportDetailsMapper;
import com.gkzf.ai.module.crm.dal.mysql.product.CrmProductMapper;
import com.gkzf.ai.module.crm.dal.mysql.product.ProductAdmittanceConditionMapper;
import com.gkzf.ai.module.crm.enums.ModelAnalysisDictEnum;
import com.gkzf.ai.module.crm.util.ExpressionEvaluator;
import com.gkzf.ai.module.crm.util.assembly.*;
import com.gkzf.ai.module.system.api.dict.DictDataApi;
import com.gkzf.ai.module.system.api.dict.dto.DictDataRespDTO;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;

import static com.gkzf.ai.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.gkzf.ai.module.crm.enums.ErrorCodeConstants.USER_CREDIT_REPORT_ADMITTANCE_CONDITION_NOT_EXISTS;
import static com.gkzf.ai.module.crm.enums.ModelAnalysisDictEnum.*;
import static com.gkzf.ai.module.crm.util.AnalysisJsonObjectUtils.*;
import static com.gkzf.ai.module.crm.util.AnalysisJsonObjectUtils.LOANS;
import static com.gkzf.ai.module.crm.util.assembly.AssemblyCreditReportDetails.*;
import static com.gkzf.ai.module.crm.util.simpleCredit.SimpleCreditExtract.RESULT;

/**
 * CRM 征信报告对应准入条件 Service 实现类
 *
 * @author 国科智飞
 */
@Service
@Slf4j
public class CreditReportAdmittanceConditionServiceImpl extends BaseService<UserCreditReportAdmittanceConditionDO> implements CreditReportAdmittanceConditionService {

    @Resource
    private CreditReportAdmittanceConditionMapper creditReportAdmittanceConditionMapper;

    @Resource
    private CreditReportLoanDetailsService creditReportLoanDetailsService;

    @Resource
    private CreditReportDetailsMapper creditReportDetailsMapper;

    @Resource
    private CreditReportDetailsService creditReportDetailsService;

    @Resource
    private IncomeDebtRatioService incomeDebtRatioService;

    @Resource
    private CreditReportLoanOverdueService creditReportLoanOverdueService;

    @Resource
    private CreditReportCreditCardDetailsService creditReportCreditCardDetailsService;

    @Resource
    private DictDataApi dictDataApi;

    @Resource
    private ProductAdmittanceConditionMapper productAdmittanceConditionMapper;

    @Resource
    private CrmProductMapper productMapper;

    @Resource
    private CreditReportBasicService creditReportBasicService;

    @Resource
    private CreditLimitService creditLimitService;

    @Resource
    private LocalWebSocketMessageSender localWebSocketMessageSender;

    /**
     * @param createReqVO 创建信息
     * @param basicDO     基础信息对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createCreditReportAdmittanceCondition(Map<String, Object> createReqVO,
                                                      CreditReportBasicDO basicDO, String channelType) {
        UserCreditReportAdmittanceConditionDO admittanceConditionDO = new UserCreditReportAdmittanceConditionDO();
        CreditReportDetailsSaveReqVO detailsDO = new CreditReportDetailsSaveReqVO();
        detailsDO.setChannelType(channelType);
        // 解析 查询记录json
        Map<String, List<OverdueRecordVo>> overdueMap = new LinkedHashMap<>();
        // 解析 查询记录json
        calculateOverdueStatistics(createReqVO, overdueMap, detailsDO, basicDO, admittanceConditionDO);

        admittanceConditionDO.setCreditReportOverdueJson(JSON.toJSONString(overdueMap));
        // 统计
        getStatistics(admittanceConditionDO, detailsDO);
        // 负债白户
        detailsDO.setCreditReportWhiteType(0);
        // 插入关联ID
        admittanceConditionDO.setCreditBasicId(basicDO.getId());
        // 计算年龄
        admittanceConditionDO.setAge(getAge(basicDO.getIdNumber()));
        // 计算性别
        admittanceConditionDO.setGender(getGender(basicDO.getIdNumber()));
        if (Objects.isNull(admittanceConditionDO.getCreditReportJudicialMonths())) {
            admittanceConditionDO.setCreditReportJudicialMonths(0);
        }
        // 插入详情表
        CreditReportAdmittanceConditionSaveReqVO creditReportAdmittanceConditionSaveReqVO = new CreditReportAdmittanceConditionSaveReqVO();
        BeanUtils.copyProperties(admittanceConditionDO, creditReportAdmittanceConditionSaveReqVO);
        creditReportAdmittanceConditionSaveReqVO.setTenantId(TenantContextHolder.getTenantId());
        creditReportAdmittanceConditionSaveReqVO.setCreator(basicDO.getCreator());
        creditReportAdmittanceConditionSaveReqVO.setIdNumber(basicDO.getIdNumber());
        // 异步 传入关联 ID 和 创建人ID 和 修改人ID
        detailsDO.setCreditBasicId(basicDO.getId());
        detailsDO.setCreator(basicDO.getCreator());
        detailsDO.setUpdater(basicDO.getCreator());
        // 组装征信详情拼接成字符串 ai解析成自然语言
//        String creditReport = analysisCreditReport(detailsDO);
//        detailsDO.setCreditAnalysis(creditReport);
        // 更新/添加 用户准入条件
        updateCreditReportAdmittanceConditionXml(creditReportAdmittanceConditionSaveReqVO);
        // 获取并更新信用分
        creditReportDetailsService.statisticsCreditScore(detailsDO, creditReportAdmittanceConditionSaveReqVO);
        // 插入二次解析详情表
        Long creditReportDetailsId = creditReportDetailsService.createCreditReportDetails(detailsDO);
        // 插入详情对应贷款明细表
        creditReportLoanDetailsService.createCreditReportLoanDetails(detailsDO.getLoanOverdueDetailsList(), creditReportDetailsId, basicDO.getCreator());
        // 插入详情对应信用卡明细表
        creditReportCreditCardDetailsService.createCreditReportCreditCardDetails(detailsDO.getLoanOverdueCreditCardDetailsList(), creditReportDetailsId, basicDO.getCreator());
        // 插入详情对应逾期明细表
        creditReportLoanOverdueService.createCreditReportLoanOverdue(detailsDO.getLoanOverdueList(), creditReportDetailsId, basicDO.getCreator());
    }

    @Override
    public void createCreditReportAdmittanceCondition(Long creditBasicId) {
        UserCreditReportAdmittanceConditionDO admittanceConditionDO = new UserCreditReportAdmittanceConditionDO();
        admittanceConditionDO.setCreditBasicId(creditBasicId);
        creditReportAdmittanceConditionMapper.insert(admittanceConditionDO);
        CreditReportDetailsDO detailsDO = new CreditReportDetailsDO();
        detailsDO.setCreditBasicId(creditBasicId);
        creditReportDetailsMapper.insert(detailsDO);
    }


    /**
     * 组装征信详情拼接成字符串 ai解析成自然语言
     *
     * @param detailsDO 征信报告详情
     */
    public String analysisCreditReport(CreditReportDetailsSaveReqVO detailsDO) {
        // 征信解析的字段
        String creditAnalysis = assemblingPersonalCreditReportDetails(detailsDO);
        log.info("征信解析的字段:{}",creditAnalysis);
        DictDataRespDTO dictDataRespDTO = dictDataApi.parseDictData(DICT_TYPT.getCode(), ADMIN_DATA_ANALYZE.getCode());
        try {
            Map<String, Object> param = new LinkedHashMap<>();
            param.put("user_data", URLEncoder.encode(creditAnalysis, StandardCharsets.UTF_8));
            param.put("app_id", APP_ID.getCode());
            log.info("征信解析参数:{}",JSON.toJSONString(param));
            String creditAnalysisResp = HttpUtil.post(dictDataRespDTO.getValue() , JSON.toJSONString(param));
            log.info("征信解析结果:{}",creditAnalysisResp);
            Map<String, Object> reqMap = JSON.parseObject(creditAnalysisResp, new TypeReference<>() {
            });
            if (reqMap.containsKey(RESULT)) {
                if (null != detailsDO.getId()) {
                    detailsDO.setCreditAnalysis(reqMap.get("result").toString());
                    creditReportDetailsMapper.updateById(BeanUtils.toBean(detailsDO, CreditReportDetailsDO.class));
                }
                return reqMap.get(RESULT).toString();
            }
        }catch (Exception e) {
            log.error("al分析结果异常:{}",e.getMessage());
        }
        return "";
    }


    /**
     * 公共方法
     * 解析查询记录
     * 解析机构查询
     */
    public void analysisQueryRecord(String creditReportQueryJson, Consumer<List<QueryLimitVo>> consumer) {
        if (StringUtils.isNotBlank(creditReportQueryJson)) {
            List<QueryLimitVo> mapRecord = JSON.parseObject(creditReportQueryJson, new TypeReference<>() {
            });
            if (mapRecord != null && !mapRecord.isEmpty()) {
                List<QueryLimitVo> list = mapRecord.stream().filter(item -> item.getQueryLimitWay() == 1).toList();
                if (!list.isEmpty()) {
                    consumer.accept(list);
                }
            }
        } else {
            consumer.accept(new ArrayList<>());
        }
    }


    /**
     * 公共方法
     * 解析查询记录
     * 解析机构查询
     */
    public void analysisQueryRecord(String creditReportQueryJson, Integer queryLimitWay, Consumer<List<QueryLimitVo>> consumer) {
        if (StringUtils.isNotBlank(creditReportQueryJson)) {
            List<QueryLimitVo> mapRecord = JSON.parseObject(creditReportQueryJson, new TypeReference<>() {
            });
            if (mapRecord != null && !mapRecord.isEmpty()) {
                List<QueryLimitVo> list = mapRecord.stream().filter(item -> Objects.equals(item.getQueryLimitWay(), queryLimitWay)).toList();
                if (!list.isEmpty()) {
                    consumer.accept(list);
                }
            }
        } else {
            consumer.accept(new ArrayList<>());
        }
    }

    /**
     * 组装个人征信报告详情
     *
     * @return 征信报告详情
     */
    @Override
    public String assemblingPersonalCreditReportDetails(CreditReportDetailsSaveReqVO detailsDO) {
        /*
           查询记录情况
         */
        StringBuilder queryRecord = new StringBuilder();
        analysisQueryRecord(detailsDO.getCreditReportQueryJson(), queryLimitVoList -> {
            for (QueryLimitVo queryLimitVo : queryLimitVoList) {
                queryRecord.append("近").append(queryLimitVo.getQueryLimitMonths()).append("个月").append(queryLimitVo.getQueryLimitMaxCount()).append("次").append(COMMA);
            }
        });
        /*
            解析逾期情况
         */
        StringBuilder loanOverdue = new StringBuilder();
        StringBuilder creditCardOverdue = new StringBuilder();
        if (StringUtils.isNotBlank(detailsDO.getCreditReportOverdueJson())) {
            Map<String, List<OverdueRecordVo>> mapOverdue = JSON.parseObject(detailsDO.getCreditReportOverdueJson(), new TypeReference<>() {
            });
            if (mapOverdue.containsKey(LOANS)) {
                List<OverdueRecordVo> overdueRecordVos = mapOverdue.get(LOANS);
                overdueRecord(overdueRecordVos, loanOverdue);
            }
            if (mapOverdue.containsKey(CREDITCARD)) {
                List<OverdueRecordVo> overdueRecordVos = mapOverdue.get(CREDITCARD);
                overdueRecord(overdueRecordVos, creditCardOverdue);
            }
        }
        StringBuilder details = new StringBuilder();
        details.append("负债总额:").append(detailsDO.getTotalLiabilities()).append("元")
                .append(COMMA).append("贷款余额:").append(Optional.ofNullable(detailsDO.getDebtCyclicalGrossAmount()).orElse(BigDecimal.ZERO)).append("元")
                .append(COMMA).append("信用卡已使用额度:").append(Optional.ofNullable(detailsDO.getCreditCardUsedCredit()).orElse(BigDecimal.ZERO)).append("元")
                .append(COMMA).append("月还款总额:").append(detailsDO.getLoanOverdueDetailsList().stream().filter(item -> StringUtils.isNotBlank(item.getMonthlyRepayment()))
                        .map(item -> new BigDecimal(item.getMonthlyRepayment())).reduce(BigDecimal.ZERO, BigDecimal::add)).append("元")
                .append(COMMA).append("信用卡当前使用率:").append(Optional.ofNullable(detailsDO.getCreditCardCurrentRate()).orElse(BigDecimal.ZERO)).append("%")
                .append(COMMA).append("信用卡近6个月平均使用率:").append(Optional.ofNullable(detailsDO.getCreditCardMonthRete()).orElse(BigDecimal.ZERO)).append("%")
                .append(COMMA).append("非银行机构数 :").append(Optional.ofNullable(detailsDO.getNonBankingOrganizationAccount()).orElse(0)).append("个")
                .append(COMMA).append("贷款机构数:").append(Optional.of(detailsDO.getNonBankingOrganizationAccount() + detailsDO.getBankingOrganizationAccount()).orElse(0)).append("个").append(COMMA);
        if (!StringUtils.isNotBlank(loanOverdue) && !StringUtils.isNotBlank(creditCardOverdue)) {
            details.append(COMMA).append("逾期情况:无").append(COMMA);
        } else {
            if (StringUtils.isNotBlank(loanOverdue)) {
                details.append("贷款逾期情况:").append(loanOverdue);
            }
            if (StringUtils.isNotBlank(creditCardOverdue)) {
                details.append("信用卡逾期情况:").append(creditCardOverdue);
            }
        }
        if (StringUtils.isNotBlank(queryRecord)) {
            details.append("机构查询记录情况:").append(queryRecord, 0, queryRecord.length() - 1);
        } else {
            details.append("机构查询记录情况:无");
        }
        return details.toString();

    }

    private static void overdueRecord(List<OverdueRecordVo> overdueRecordVos, StringBuilder loanOverdue) {
        overdueRecordVos.forEach(overdueRecordVo -> {
            // 获取并处理各个字段
            String continuousOverdueMonths = getValueSafely(overdueRecordVo.getContinuousOverdueMonths());
            String maxMonthsOverdueMonths = getValueSafely(overdueRecordVo.getMaxMonthsOverdueMonths());
            String maxMonthsOverdueAmountMonths = getValueSafely(overdueRecordVo.getMaxMonthsOverdueAmountMonths());
            String overUeRecordMonths = getValueSafely(overdueRecordVo.getOverUeRecordMonths());

            // 只要有一个不为0，就拼接数据
            if (!"0".equals(continuousOverdueMonths)
                    || !"0".equals(maxMonthsOverdueMonths)
                    || !"0".equals(maxMonthsOverdueAmountMonths)
                    || !"0".equals(overUeRecordMonths)) {

                String monthsDescription = getString(overdueRecordVo); // 假设这个方法是安全的

                loanOverdue.append(monthsDescription)
                        .append(" 逾期次数:").append(overUeRecordMonths).append(COMMA)
                        .append("最大连续次数:").append(continuousOverdueMonths).append(COMMA)
                        .append("最长逾期月数:").append(maxMonthsOverdueMonths).append(COMMA)
                        .append("最高逾期金额:").append(maxMonthsOverdueAmountMonths).append("元").append(COMMA);
            }
        });
    }

    /**
     * 安全地从字符串中提取指定索引位置的值，如果失败返回 "0"
     *
     * @param input 输入字符串，如 "A,B,C"
     * @return 提取到的值或默认值 "0"
     */
    private static String getValueSafely(String input) {
        if (input == null || input.trim().isEmpty()) {
            return "0";
        }

        String[] parts = input.split(COMMA);
        if (parts.length <= 1) {
            return "0";
        }

        return parts[1];
    }

    private static String getString(OverdueRecordVo overdueRecordVo) {
        String months = overdueRecordVo.getContinuousOverdueMonths().split(COMMA)[0];
        String monthsDescription = "";
        switch (months) {
            case "1" -> monthsDescription = "当前逾期";
            case "6" -> monthsDescription = "近半年逾期";
            case "12" -> monthsDescription = "近一年逾期";
            case "24" -> monthsDescription = "近二年逾期";
            case "60" -> monthsDescription = "近五年逾期";
            default -> {
            }
        }
        return monthsDescription;
    }

    /**
     * 根据上下文计算可贷点
     *
     * @param updateReqVO 补充信息对象
     * @return 可贷点字符串逗号隔开
     */
    public String getLoanUses(CreditReportAdmittanceConditionSaveReqVO updateReqVO) {
        StringBuilder loanUses = new StringBuilder();
        Integer isHave = 1;
        // 使用映射存储条件字段和对应的值
        Map<Predicate<CreditReportAdmittanceConditionSaveReqVO>, Integer> conditionMappings = new LinkedHashMap<>();
        conditionMappings.put(reqVO -> reqVO.getIsPayTaxes() != null && reqVO.getIsPayTaxes().equals(isHave), 1);
        conditionMappings.put(reqVO -> reqVO.getIsSocialSecurity() != null && reqVO.getIsSocialSecurity().equals(isHave), 2);
        conditionMappings.put(reqVO -> reqVO.getIsReserveFund() != null && reqVO.getIsReserveFund().equals(isHave), 3);
        conditionMappings.put(reqVO -> reqVO.getIsMortgage() != null && reqVO.getIsMortgage().equals(isHave), 4);
        conditionMappings.put(reqVO -> reqVO.getIsFullPayment() != null && reqVO.getIsFullPayment().equals(isHave), 7);
        conditionMappings.put(reqVO -> reqVO.getIsHypothecate() != null && reqVO.getIsHypothecate().equals(isHave), 8);
        conditionMappings.put(reqVO -> reqVO.getIsMortgageVehicle() != null && reqVO.getIsMortgageVehicle().equals(isHave), 14);
        conditionMappings.put(reqVO -> reqVO.getIsFullPaymentVehicle() != null && reqVO.getIsFullPaymentVehicle().equals(isHave), 15);

        // 遍历条件映射，满足条件则添加对应的值
        conditionMappings.forEach((condition, value) -> {
            if (condition.test(updateReqVO)) {
                loanUses.append(value).append(COMMA);
            }
        });
        if (StringUtils.isNotBlank(loanUses)) {
            return loanUses.toString();
        }
        return "";
    }


    /**
     * 根据上下文获得司法类型
     *
     * @return 返回司法类型字符串逗号隔开
     */
    public String getJudicialType(CreditReportAdmittanceConditionSaveReqVO updateReqVO) {
        StringBuilder judicialType = new StringBuilder();
        Map<Predicate<CreditReportAdmittanceConditionSaveReqVO>, Integer> predicateIntegerMap = new HashMap<>();
        predicateIntegerMap.put(req -> Objects.nonNull(req.getIsIllegalRecord()) && req.getIsIllegalRecord() == 1, 2);
        predicateIntegerMap.put(req -> Objects.nonNull(req.getIsDiscreditedPerson()) && req.getIsDiscreditedPerson() == 1, 1);
        predicateIntegerMap.forEach((item, value) -> {
            if (item.test(updateReqVO)) {
                judicialType.append(value).append(COMMA);
            }

        });
        if (StringUtils.isNotBlank(judicialType)) {
            return judicialType.toString();
        }
        return "";

    }


    /**
     * 获得CRM 征信报告对应准入条件
     *
     * @param creditBasicId 编号
     * @return CRM 征信报告对应准入条件
     */
    @Override
    public UserCreditReportAdmittanceConditionDO getCreditReportAdmittanceCondition(Long creditBasicId) {
        LambdaQueryWrapper<UserCreditReportAdmittanceConditionDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserCreditReportAdmittanceConditionDO::getCreditBasicId, creditBasicId);
        List<UserCreditReportAdmittanceConditionDO> userCreditReportAdmittanceConditionDOS = creditReportAdmittanceConditionMapper.selectList(queryWrapper);
        if (userCreditReportAdmittanceConditionDOS.isEmpty()) {
            throw exception(USER_CREDIT_REPORT_ADMITTANCE_CONDITION_NOT_EXISTS);
        }
        return userCreditReportAdmittanceConditionDOS.get(0);
    }


    /**
     * 统计
     * 查询五级分类
     * 负债总额
     * 拼装 逾期记录格式
     *
     * @param admittanceConditionDO 准入条件对象
     * @param detailsDO             基础信息对象
     * @return 计算好的准入条件对象
     */

    public UserCreditReportAdmittanceConditionDO getStatistics(UserCreditReportAdmittanceConditionDO admittanceConditionDO,
                                                               CreditReportDetailsSaveReqVO detailsDO) {
        // 五级分类
        admittanceConditionDO.setCreditReportFiveLevel(detailsDO.getCreditReportFiveLevel());

        // 负债总额
        creditReportDetailsService.getTotalLiabilities(detailsDO);
        // 循环得到负债1-6类型记录
        getQueryRecordJson(admittanceConditionDO, detailsDO);
        // 负债情况json  和 查询记录json
        detailsDO.setCreditReportOverdueJson(admittanceConditionDO.getCreditReportOverdueJson());
        detailsDO.setCreditReportQueryJson(admittanceConditionDO.getCreditReportQueryJson());
        return admittanceConditionDO;
    }

    private void getQueryRecordJson(UserCreditReportAdmittanceConditionDO admittanceConditionDO, CreditReportDetailsSaveReqVO detailsDO) {
        List<LiabilityVo> liabilityVoList = new ArrayList<>();
        List<DictDataRespDTO> creditReportOverdueCreditCardsList = dictDataApi.getDictDataList("crm_credit_report_liability");
        for (DictDataRespDTO entry : creditReportOverdueCreditCardsList) {
            LiabilityVo liabilityVo = new LiabilityVo();
            switch (entry.getValue()) {
                case "1":
                    liabilityVo.setLiabilityRequirementType(Integer.valueOf(entry.getValue()));
                    liabilityVo.setLiabilityRequirementAmount(defaultValue(detailsDO.getNonBankingOrganizationAccount()));
                    break;
                case "2":
                    liabilityVo.setLiabilityRequirementType(Integer.valueOf(entry.getValue()));
                    liabilityVo.setLiabilityRequirementAmount(defaultValue(detailsDO.getNonBankingOrganizationMoney()));
                    break;
                case "5":
                    liabilityVo.setLiabilityRequirementType(Integer.valueOf(entry.getValue()));
                    liabilityVo.setLiabilityRequirementAmount(defaultValue(detailsDO.getCreditLoanMoneyCount()));
                    break;
                case "6":
                    liabilityVo.setLiabilityRequirementType(Integer.valueOf(entry.getValue()));
                    liabilityVo.setLiabilityRequirementAmount(defaultValue(detailsDO.getCreditLoanOrgCount()));
                    break;
                case "3":
                    liabilityVo.setLiabilityRequirementType(Integer.valueOf(entry.getValue()));
                    liabilityVo.setLiabilityRequirementAmount(defaultValue(detailsDO.getCreditCardMonthRete()));
                    break;
                case "4":
                    liabilityVo.setLiabilityRequirementType(Integer.valueOf(entry.getValue()));
                    liabilityVo.setLiabilityRequirementAmount(defaultValue(detailsDO.getCreditCardCurrentRate()));
                    break;
                default:
                    break;
            }
            liabilityVoList.add(liabilityVo);
        }

        admittanceConditionDO.setCreditReportLiabilityJson(JSON.toJSONString(liabilityVoList));
    }


    public void calculateOverdueStatistics(Map<String, Object> financeMap,
                                           Map<String, List<OverdueRecordVo>> overdueMap,
                                           CreditReportDetailsSaveReqVO detailsDO,
                                           CreditReportBasicDO creditReportBasicDO,
                                           UserCreditReportAdmittanceConditionDO admittanceConditionDO) {
        List<OverdueRecordVo> overdueSummary = new ArrayList<>();
        if (financeMap.containsKey(KEY_BASIC)) {
            String creditReportJson = (String) financeMap.get(KEY_BASIC);
            JSONObject jsonObject = JSON.parseObject(creditReportJson);
            Map<String, Object> creditMap = JSON.parseObject((String) jsonObject.get(JSON_RESULT_KEY), new TypeReference<>() {
            });
            // 征信基本信息
            AssembleBasicInfo assembleBasicInfo = new AssembleBasicInfo();
            assembleBasicInfo.assemblyBasicInfo(creditMap, creditReportBasicDO, detailsDO);
            // 循环贷一 二 非循环贷 贷记卡信息汇总
            LoanSummary loanSummary = new LoanSummary();
            loanSummary.getLoanSummary(creditMap, detailsDO);
            // 公共信息汇总
            PublicInformationSummary publicInformationSummary = new PublicInformationSummary();
            publicInformationSummary.getPublicInformationSummary(creditMap, detailsDO);
        }
        if (financeMap.containsKey(KEY_MODEL_LOAN)) {
            String loanReportJson = (String) financeMap.get(KEY_MODEL_LOAN);
            JSONObject jsonObject = JSON.parseObject(loanReportJson);
            Map<String, Object> map = JSON.parseObject((String) jsonObject.get(JSON_RESULT_KEY), new TypeReference<>() {
            });
            // 逾期明细
            OverdueInfoDetails overdueInfoDetails = new OverdueInfoDetails();
            overdueInfoDetails.getCreditReportLoanOverdue(map, detailsDO);
            // 逾期汇总
            OverdueRecordSummary overdueRecordSummary = new OverdueRecordSummary();
            overdueRecordSummary.getOverdueRecordLoansVoList(map, overdueMap, LOANS, overdueSummary);
            // 征信信息
            CreditReportInfo creditReportInfo = new CreditReportInfo();
            creditReportInfo.getCreditReportInfo(map, detailsDO);
            // 贷款未结清账户明细列表
            LoanAccountDetails loanAccountDetails = new LoanAccountDetails();
            loanAccountDetails.getLoanAccountDetails(map, detailsDO);
            JSONArray errorJsonArray = (JSONArray) map.get(ERROR_ACCOUNTS_KEY);
            if (!errorJsonArray.isEmpty()) {
                log.info("获取异常状态列表:{}", errorJsonArray);
                detailsDO.setErrorJson(errorJsonArray.toJSONString());
            }
        }
        if (financeMap.containsKey(KEY_MODEL_CREDIT_CARD)) {
            String creditReportJson = (String) financeMap.get(KEY_MODEL_CREDIT_CARD);
            JSONObject jsonObject = JSON.parseObject(creditReportJson);
            Map<String, Object> creditMap = JSON.parseObject((String) jsonObject.get(JSON_RESULT_KEY), new TypeReference<>() {
            });
            // 逾期明细
            OverdueInfoDetails overdueInfoDetails = new OverdueInfoDetails();
            overdueInfoDetails.getCreditReportLoanOverdue(creditMap, detailsDO);

            // 逾期汇总
            OverdueRecordSummary overdueRecordSummary = new OverdueRecordSummary();
            overdueRecordSummary.getOverdueRecordLoansVoList(creditMap, overdueMap, CREDITCARD, overdueSummary);

            // 信用卡 未结清账户明细列表
            CreditAccountDetails creditAccountDetails = new CreditAccountDetails();
            creditAccountDetails.getCreditAccountDetails(creditMap, detailsDO);

        }
        if (financeMap.containsKey(KEY_QUERY_RECORD)) {
            String creditReportJson = (String) financeMap.get(KEY_QUERY_RECORD);
            JSONObject jsonObject = JSON.parseObject(creditReportJson);
            Map<String, Object> creditMap = JSON.parseObject((String) jsonObject.get("result"), new TypeReference<>() {
            });
            List<DictDataRespDTO> queryLimitDictDataList = dictDataApi.getDictDataList(ModelAnalysisDictEnum.QUERY_RECORD_COLLECT.getCode());
            AssembleQueryRecordDetails assembleQueryRecordDetails = new AssembleQueryRecordDetails(queryLimitDictDataList);
            assembleQueryRecordDetails.getAssembleQueryRecordDetails(creditMap, admittanceConditionDO, detailsDO);
        }
        /*
            逾期汇总计算
         */
        Map<String, Integer> overdue = new LinkedHashMap<>();
        overdueSummary.forEach(item -> {
            // 直接调用辅助方法处理每一个可能的逾期字段
            processOverdueField(item.getContinuousOverdueMonths(), "continuousOverdueMonths", overdue, COMMA, "2");
            processOverdueField(item.getMaxMonthsOverdueMonths(), "maxMonthsOverdueMonths", overdue, COMMA, "2");
            processOverdueField(item.getOverUeRecordMonths(), "overUeRecordMonths", overdue, COMMA, "1");
            processOverdueField(item.getMaxMonthsOverdueAmountMonths(), "maxMonthsOverdueAmountMonths", overdue, COMMA, "2");
        });
        // 如果聚合后的 map 不为空，则按类别过滤并处理数据
        if (!overdue.isEmpty()) {
            List<OverdueRecordVo> overdueRecordList = getOverdueRecordVos(overdue);
            overdueMap.put("summary", overdueRecordList);
        }

    }


    /**
     * 提交h5页面 用户提交信息 修改基本信息状态
     * 二维码只能生成一次 不能重复生成
     *
     * @param updateReqVO 更新信息
     */
    @Transactional
    @Override
    public void updateCreditReportAdmittanceCondition(CreditReportAdmittanceConditionSaveReqVO updateReqVO, Integer isSubmitQpCode) {
        // 更新
        log.info("二维码上传数据转换前:{}", JSON.toJSONString(updateReqVO));
        UserCreditReportAdmittanceConditionDO updateObj = BeanUtils.toBean(updateReqVO, UserCreditReportAdmittanceConditionDO.class);
        LambdaQueryWrapper<UserCreditReportAdmittanceConditionDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserCreditReportAdmittanceConditionDO::getCreditBasicId, updateReqVO.getCreditBasicId());
        updateObj.setLoanUses(Optional.ofNullable(getLoanUses(updateReqVO)).orElse(""));
        updateObj.setCreditReportJudicialType(Optional.ofNullable(getJudicialType(updateReqVO)).orElse(""));
        if (null != updateReqVO.getTenantId()) {
            TenantContextHolder.setTenantId(updateReqVO.getTenantId());
        }
        CreditReportDetailsRespVO creditReportDetails = creditReportDetailsService.getCreditReportDetails(updateReqVO.getCreditBasicId());
        // 获取并更新信用分
        creditReportDetailsService.statisticsCreditScore(BeanUtils.toBean(creditReportDetails, CreditReportDetailsSaveReqVO.class), updateReqVO);

        List<UserCreditReportAdmittanceConditionDO> admittanceConditionDOList = creditReportAdmittanceConditionMapper.selectList(queryWrapper);
        /*
          判断 二维码先填好  还是 先解析好
         */
        log.info("二维码上传数据转换后:{}", JSON.toJSONString(updateObj));
        if (admittanceConditionDOList.isEmpty()) {
            creditReportAdmittanceConditionMapper.insert(updateObj);
        } else {
            creditReportAdmittanceConditionMapper.update(updateObj, queryWrapper);
        }

        creditReportBasicService.updateIsSubmitQpCode(updateReqVO.getCreditBasicId(), updateReqVO.getEducation());
        if (null != updateReqVO.getTenantId()) {
            log.info("推送二维码提交消息： 用户类型:{}，用户ID:{}", UserTypeEnum.ADMIN.getValue(), updateReqVO.getUserId());
            Map<String, String> resultMap = new HashMap<>();
            resultMap.put("isSubmit", "1");
            localWebSocketMessageSender.send(UserTypeEnum.ADMIN.getValue(), updateReqVO.getUserId(), "creditReport", JSON.toJSONString(resultMap));
        }
    }


    public Long getDetailsIdByBasicId(Long creditBasicId) {
        LambdaQueryWrapper<CreditReportDetailsDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CreditReportDetailsDO::getCreditBasicId, creditBasicId);

        return creditReportDetailsMapper.selectOne(queryWrapper).getId();
    }


    public Long getBasicIdByConditionId(Long creditBasicId) {
        LambdaQueryWrapper<UserCreditReportAdmittanceConditionDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserCreditReportAdmittanceConditionDO::getCreditBasicId, creditBasicId);
        return creditReportAdmittanceConditionMapper.selectOne(queryWrapper).getId();
    }

    /**
     * 修改补充信息 只修改 解析完成后的某些字段 不修改全部
     *
     * @param updateReqVO 更新信息
     */
    @Transactional
    public void updateCreditReportAdmittanceConditionXml(CreditReportAdmittanceConditionSaveReqVO updateReqVO) {
        // 更新
        UserCreditReportAdmittanceConditionDO updateObj = BeanUtils.toBean(updateReqVO, UserCreditReportAdmittanceConditionDO.class);
        LambdaQueryWrapper<UserCreditReportAdmittanceConditionDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Objects.nonNull(updateReqVO.getCreditBasicId()), UserCreditReportAdmittanceConditionDO::getCreditBasicId, updateReqVO.getCreditBasicId());
        if (null != updateReqVO.getTenantId()) {
            TenantContextHolder.setTenantId(updateReqVO.getTenantId());
        }
        List<UserCreditReportAdmittanceConditionDO> admittanceConditionDOList = creditReportAdmittanceConditionMapper.selectList(queryWrapper);
        /*
          判断 二维码先填好  还是 先解析好
         */
        if (admittanceConditionDOList.isEmpty()) {
            creditReportAdmittanceConditionMapper.insertCondition(updateObj);
        } else {
            creditReportAdmittanceConditionMapper.updateConditionById(updateObj);
        }

    }

    /**
     * 提交h5页面 用户提交信息 修改基本信息状态
     * 二维码只能生成一次 不能重复生成
     *
     * @param updateReqVO 更新信息
     */
    @Transactional
    @Override
    public void updateCreditReportAdmittanceCondition(CreditReportDetailsSaveReqVO updateReqVO, String idNumber, CreditReportBasicSaveReqVO basicRespVO) {
        // 更新
        UserCreditReportAdmittanceConditionDO updateObj = BeanUtils.toBean(updateReqVO, UserCreditReportAdmittanceConditionDO.class);
        if (StringUtils.isNotBlank(idNumber)) {
            updateObj.setAge(getAge(idNumber));
        }
        if (StringUtils.isNotBlank(basicRespVO.getGender())) {
            updateObj.setGender(Objects.equals(basicRespVO.getGender(), "男") ? 0 : 1);
        }
        // 负责情况json
        getQueryRecordJson(updateObj, updateReqVO);
        creditReportAdmittanceConditionMapper.updateConditionById(updateObj);
        UserCreditReportAdmittanceConditionDO admittanceCondition = getCreditReportAdmittanceCondition(updateReqVO.getCreditBasicId());
        // 获取并更新信用分
        creditReportDetailsService.statisticsCreditScore(updateReqVO, BeanUtils.toBean(admittanceCondition, CreditReportAdmittanceConditionSaveReqVO.class));
    }

    /**
     * 获得CRM 征信报告对应准入条件贷款目标
     *
     * @param creditBasicId 编号
     * @return CRM 征信报告对应准入条件
     */
    public BigDecimal getLoanObjective(Long creditBasicId) {
        UserCreditReportAdmittanceConditionDO admittanceConditionDO =
                creditReportAdmittanceConditionMapper.selectOne(
                        new LambdaQueryWrapper<UserCreditReportAdmittanceConditionDO>()
                                .eq(UserCreditReportAdmittanceConditionDO::getCreditBasicId, creditBasicId));
        if (Objects.isNull(admittanceConditionDO)) {
            return BigDecimal.ZERO;
        }
        return admittanceConditionDO.getLoanObjective();
    }

    /**
     * 计算产品收入负债比
     *
     * @param creditBasicId 基本信息id
     * @return 有额度产品的结果
     */
    @SneakyThrows
    @Override
    public Map<String, String> getIncomeDebtRatio(Long creditBasicId) {
        Map<String, String> retuenMap = new HashMap<>();
        Long detailsId = getDetailsIdByBasicId(creditBasicId);
        Map<String, String> calculationResultMap = new LinkedHashMap<>();
        LambdaQueryWrapper<CrmProductDO> queryProductWrapper = new LambdaQueryWrapper<>();
        queryProductWrapper.eq(CrmProductDO::getStatus, "0");
        /*
          获取产品准入中 所有选中收入负债比的产品
         */
        List<CrmProductDO> productDOList = productMapper.selectList(queryProductWrapper);
        productDOList.forEach(item -> {
            if (StringUtils.isNotBlank(item.getQuotaFormula())) {
                /*
                    计算额度
                */
                List<QuotaFormula> quotaFormulaValue = JSON.parseObject(item.getQuotaFormula(), new TypeReference<>() {
                });
                log.info("开始测算额度产品编号:{}", item.getNo());
                BigDecimal bigDecimal = calculationCreditLimit(quotaFormulaValue, detailsId, calculationResultMap);
                retuenMap.put(item.getNo(), bigDecimal.toString());
                log.info("额度测算：产品编号：{},额度：{}", item.getNo(), bigDecimal);
            }
        });


        LambdaQueryWrapper<ProductAdmittanceConditionDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProductAdmittanceConditionDO::getIsIncomeDebtRatio, "1");
        /*
          获取产品准入中 所有选中收入负债比的产品
         */
        List<ProductAdmittanceConditionDO> admittanceConditionList = productAdmittanceConditionMapper.selectList(queryWrapper);
        List<IncomeDebtRatioVo> incomeDebtRatioVos = new ArrayList<>();
        admittanceConditionList.forEach(item -> {

            /*
                解析产品公式
                将公式转换成具体对象
             */
            List<ProductIncomeDebtRatioVo> productIncomeDebtRatioVo = JSON.parseObject(item.getIncomeDebtRatio(), new TypeReference<List<ProductIncomeDebtRatioVo>>() {
            });
            /*
               循环公式 可能多个公式对应一个产品
             */
            productIncomeDebtRatioVo.forEach(productIncomeDebtRatio -> {
                IncomeDebtRatioVo incomeDebtRatioVo = new IncomeDebtRatioVo();
                /*
                    将公式中的中文条件值 替换成具体值
                 */
                log.info("解析产品编号:{} 解析收入负债比公式:{}", item.getNo(), JSON.toJSONString(productIncomeDebtRatio));
                replaceFormulaNoun(productIncomeDebtRatio.getDenominator(), detailsId, calculationResultMap);
                replaceFormulaNoun(productIncomeDebtRatio.getMolecule(), detailsId, calculationResultMap);
                /*
                    计算公式结果
                 */
                log.info("解析产品编号:{} 解析收入负债比公式:{}", item.getNo(), JSON.toJSONString(productIncomeDebtRatio));
                // 计算出 分子(负债)的总和
                BigDecimal molecule = ExpressionEvaluator.evaluate(productIncomeDebtRatio.getMolecule());
                log.info("分子结果：{}", molecule);
                // 计算出 分母(收入)的总和
                BigDecimal denominator = ExpressionEvaluator.evaluate(productIncomeDebtRatio.getDenominator());
                log.info("分母结果：{}", denominator);
                // 收入负债比结果
                String incomeDebtRatio = getIncomeDebtRatio(molecule, denominator);
                log.info("收入负债比结果：{}", incomeDebtRatio);
                // 组装这个公式的集合
                incomeDebtRatioVo.setUserRatio(incomeDebtRatio);
                incomeDebtRatioVo.setProductRatio(productIncomeDebtRatio.getResult());
                incomeDebtRatioVo.setRatio(productIncomeDebtRatio.getRatio());
                incomeDebtRatioVo.setProductNo(item.getNo());
                incomeDebtRatioVo.setIndex(productIncomeDebtRatio.getIndex());
                incomeDebtRatioVos.add(incomeDebtRatioVo);
            });
        });
        if (incomeDebtRatioVos.isEmpty()) {
            return retuenMap;
        }
        retuenMap.put("incomeDebtRatio", JSON.toJSONString(incomeDebtRatioVos));
        return retuenMap;
    }


    /**
     * 计算收入负债比
     *
     * @param molecule    分子
     * @param denominator 分母
     * @return 负债比值
     */
    private static String getIncomeDebtRatio(BigDecimal molecule, BigDecimal denominator) {
        String incomeDebtRatio = null;
        // 判断 如果分子(负债) 小于等于 0 则不计算 负债率 0%
        if (molecule.compareTo(BigDecimal.ZERO) <= 0) {
            incomeDebtRatio = "0";
        }
        // 如果 分母(收入) 小于等于 0  则直接匹配不通过 负债率 100%
        else if (denominator.compareTo(BigDecimal.ZERO) <= 0 && molecule.compareTo(BigDecimal.ZERO) <= 0) {
            incomeDebtRatio = "0";
        }// 如果 分母(收入) 小于等于 0 分子(收入)不等于0 则分母直接等于结果 则直接匹配不通过 负债率 100%
        else if (denominator.compareTo(BigDecimal.ZERO) <= 0 && molecule.compareTo(BigDecimal.ZERO) > 0) {
            incomeDebtRatio = molecule.toString();
        } else {
            // 计算收入负债比 分子除分母 保留2位小数 四舍五入
            incomeDebtRatio = String.valueOf(molecule.divide(denominator, 2, RoundingMode.HALF_UP));
        }
        return incomeDebtRatio;
    }

    /**
     * 替换 产品公式中的中文 换算成结果 替换 对应数值
     * 查询结果重复 所有存Map中不需要一直查询
     *
     * @param formulaNounList 贷用额度公式中的中文
     */
    public void replaceFormulaNoun(List<String> formulaNounList, Long creditReportDetailsId, Map<String, String> calculationResultMap) {
        for (int i = 0; i < formulaNounList.size(); i++) {
            String formulaNouns = formulaNounList.get(i);
            if (StringUtils.isEmpty(formulaNouns)) {
                return;
            }
            String[] formulaNoun = formulaNouns.split(":");

            switch (formulaNoun[0]) {
                case "信用贷款月还款金额" -> {
                    String monthlyRepaymentAmount;
                    if (calculationResultMap.containsKey(formulaNoun[0])) {
                        monthlyRepaymentAmount = calculationResultMap.get(formulaNoun[0]);
                        formulaNounList.set(i, monthlyRepaymentAmount);
                    } else {
                        monthlyRepaymentAmount = incomeDebtRatioService.getMonthlyRepaymentAmount(creditReportDetailsId).toString();
                        formulaNounList.set(i, monthlyRepaymentAmount);
                        calculationResultMap.put(formulaNoun[0], monthlyRepaymentAmount);
                    }
                    log.info("{}:{}", formulaNoun[0], monthlyRepaymentAmount);
                }
                case "总贷款月还款金额" -> {
                    String monthlyRepaymentAmount;
                    if (calculationResultMap.containsKey(formulaNoun[0])) {
                        monthlyRepaymentAmount = calculationResultMap.get(formulaNoun[0]);
                        formulaNounList.set(i, monthlyRepaymentAmount);
                    } else {
                        monthlyRepaymentAmount = incomeDebtRatioService.getTotalMonthlyRepaymentAmount(creditReportDetailsId).toString();
                        formulaNounList.set(i, monthlyRepaymentAmount);
                        calculationResultMap.put(formulaNoun[0], monthlyRepaymentAmount);
                    }
                    log.info("{}:{}", formulaNoun[0], monthlyRepaymentAmount);
                }
                case "信用贷款总额" -> {
                    String totalCreditLoanAmount;
                    if (calculationResultMap.containsKey(formulaNoun[0])) {
                        totalCreditLoanAmount = calculationResultMap.get(formulaNoun[0]);
                        formulaNounList.set(i, totalCreditLoanAmount);
                    } else {
                        totalCreditLoanAmount = incomeDebtRatioService.getTotalCreditLoanAmount(creditReportDetailsId).toString();
                        formulaNounList.set(i, totalCreditLoanAmount);
                        calculationResultMap.put(formulaNoun[0], totalCreditLoanAmount);
                    }
                    log.info("{}:{}", formulaNoun[0], totalCreditLoanAmount);
                }
                case "年收入" -> {
                    String annualIncome;
                    if (calculationResultMap.containsKey(formulaNoun[0])) {
                        annualIncome = calculationResultMap.get(formulaNoun[0]);
                        formulaNounList.set(i, annualIncome);
                    } else {
                        annualIncome = incomeDebtRatioService.getAnnualIncome(creditReportDetailsId).toString();
                        formulaNounList.set(i, annualIncome);
                        calculationResultMap.put(formulaNoun[0], annualIncome);
                    }
                    log.info("{}:{}", formulaNoun[0], annualIncome);
                }
                case "认定月收入" -> {
                    String monthlyIncome;
                    if (calculationResultMap.containsKey(formulaNoun[0] + formulaNoun[1])) {
                        monthlyIncome = calculationResultMap.get(formulaNoun[0] + formulaNoun[1]);
                        formulaNounList.set(i, monthlyIncome);
                    } else {
                        monthlyIncome = incomeDebtRatioService.getConcludeMonthlyIncome(creditReportDetailsId, formulaNoun[1]).toString();
                        formulaNounList.set(i, monthlyIncome);
                        calculationResultMap.put(formulaNoun[0] + formulaNoun[1], monthlyIncome);
                    }
                    log.info("{}:{}", formulaNoun[0], monthlyIncome);
                }
                case "月收入" -> {
                    String monthlyIncome;
                    if (calculationResultMap.containsKey(formulaNoun[0])) {
                        monthlyIncome = calculationResultMap.get(formulaNoun[0]);
                        formulaNounList.set(i, monthlyIncome);
                    } else {
                        monthlyIncome = incomeDebtRatioService.getMonthlyIncome(creditReportDetailsId).toString();
                        formulaNounList.set(i, monthlyIncome);
                        calculationResultMap.put(formulaNoun[0], monthlyIncome);
                    }
                    log.info("{}:{}", formulaNoun[0], monthlyIncome);
                }
                default -> {
                    if (AssembleUtils.isString(formulaNoun[0])) {
                        String balanceTotalByDetailsIdAndInstitution;
                        if (calculationResultMap.containsKey(formulaNoun[0])) {
                            balanceTotalByDetailsIdAndInstitution = calculationResultMap.get(formulaNoun[0]);
                            formulaNounList.set(i, balanceTotalByDetailsIdAndInstitution);
                        } else {
                            balanceTotalByDetailsIdAndInstitution = incomeDebtRatioService.getBalanceTotalByDetailsIdAndInstitution(creditReportDetailsId, formulaNoun[0]);
                            formulaNounList.set(i, balanceTotalByDetailsIdAndInstitution);
                            calculationResultMap.put(formulaNoun[0], balanceTotalByDetailsIdAndInstitution);
                        }
                        log.info("{}:{}", formulaNoun[0], balanceTotalByDetailsIdAndInstitution);
                    }
                }
            }
        }
    }

    /**
     * 计算可贷额度
     *
     * @param creditReportDetailsId 明细id
     * @param quotaFormulaList      额度计算表达式集合
     * @return 可贷额度
     */
    public BigDecimal calculationCreditLimit(List<QuotaFormula> quotaFormulaList, Long creditReportDetailsId, Map<String, String> calculationResultMap) {
        /*
         * 匹配前置条件
         */
        if (quotaFormulaList.isEmpty()) {
            return BigDecimal.ZERO;
        }
        CreditReportDetailsDO detailsDO = creditReportDetailsMapper.selectById(creditReportDetailsId);
        UserCreditReportAdmittanceConditionDO admittanceCondition = getCreditReportAdmittanceCondition(detailsDO.getCreditBasicId());

        /*
         * 循环遍历公式
         * 找出用户满足的公式集合
         */
        List<QuotaFormulaValue> matchPojo = new ArrayList<>();
        for (QuotaFormula quotaFormula : quotaFormulaList) {
            List<QuotaFormulaValue> formulaValue = quotaFormula.getValue();

            // 匹配上的对象
            switch (quotaFormula.getType()) {
                case 1 ->
                        matchPojo.addAll(creditLimitService.monthlyIncomePrecondition(formulaValue, admittanceCondition));
                case 2 ->
                        matchPojo.addAll(creditLimitService.propertyValuePrecondition(formulaValue, admittanceCondition));
                case 3 -> matchPojo.addAll(creditLimitService.unitPrecondition(formulaValue, admittanceCondition));
                case 4 ->
                        matchPojo.addAll(creditLimitService.mortgageMonthlyPayment(formulaValue, admittanceCondition));
                case 5 -> matchPojo.addAll(creditLimitService.providentFundMoney(formulaValue, admittanceCondition));
                default -> log.info("未知的公式类型");
            }
        }
        /*
            循环用户满足公式计算额度存储 找出最大的
         */
        List<BigDecimal> allCalculatedIncomes = new ArrayList<>();
        matchPojo.forEach(item -> {
            if (null == item) {
                allCalculatedIncomes.add(BigDecimal.ZERO);
                return;
            }
            List<String> formulaValue = item.getFormulaValue();
            replaceFormulaNoun(formulaValue, creditReportDetailsId, calculationResultMap);
            BigDecimal molecule = ExpressionEvaluator.evaluate(formulaValue);
            log.info("公式：{},计算结果：{}", JSON.toJSONString(item), molecule);
            allCalculatedIncomes.add(molecule);
        });
        return allCalculatedIncomes.stream()
                .max(BigDecimal::compareTo)
                .orElse(BigDecimal.ZERO);
    }


}
